package com.xstudio.pvzreborn.recipe.machine;

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.xstudio.pvzreborn.block.BlockNames;
import com.xstudio.pvzreborn.item.ItemManager;
import com.xstudio.pvzreborn.recipe.RecipeBase;
import com.xstudio.pvzreborn.recipe.RecipeSerializerBase;
import com.xstudio.pvzreborn.utils.Utils;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.GsonHelper;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.item.crafting.ShapedRecipe;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.annotation.ParametersAreNonnullByDefault;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@ParametersAreNonnullByDefault
public class SPCRecipe extends MachineRecipeBase {

    public static final String TYPE_ID = BlockNames.SEED_PACKET_CREATOR;

	private final Ingredient[] inputs;
	private final int requireEnergy;
	private final ItemStack output;
	private final int tick;

	public SPCRecipe(ResourceLocation id, ItemStack output, Ingredient[] inputs, int requireEnergy, int tick) {
		super(id);
		this.tick = tick;
		this.inputs = inputs;
		this.output = output;
		this.requireEnergy = requireEnergy;
	}

	@Override
	public String getTypeId() {
		return TYPE_ID;
	}

	@NotNull
	@Override
	public ItemStack getToastSymbol() {
        return ItemManager.getDefaultItemStack(BlockNames.SEED_PACKET_CREATOR);
	}

	public boolean matches(List<ItemStack> stacks, int haveEnergy) {
		boolean[] match = new boolean[inputs.length];
		Arrays.fill(match, false);
		if (haveEnergy >= requireEnergy) {
			for (ItemStack stack : stacks) {
				if (is(0, match, stack)) {
					match[0] = true;
				} else if (is(1, match, stack)) {
					match[1] = true;
				} else if (is(2, match, stack)) {
					match[2] = true;
				} else if (is(3, match, stack)) {
					match[3] = true;
				}
			}
		}
		return Utils.allTrue(match);
	}

	private boolean is(int index, boolean[] match, ItemStack stack) {
		if (index > -1 && index < inputs.length && !match[index]) {
			return inputs[index].test(stack);
		}
		return false;
	}

	@Override
	public int getTick() {
		return tick;
	}

	@Override
	public int getRequireEnergy() {
		return requireEnergy;
	}

	@Override
	public @NotNull ItemStack getResultItem() {
		return output;
	}

	public Ingredient[] getInputs() {
		return inputs;
	}

	@Override
	public boolean isShapeless(RecipeBase recipe) {
		return true;
	}

	public static class Serializer extends RecipeSerializerBase<SPCRecipe> {

		@NotNull
		@Override
		public SPCRecipe fromJson(ResourceLocation id, JsonObject json) {
			List<Ingredient> inputs = new ArrayList<>();
			for (JsonElement e : GsonHelper.getAsJsonArray(json, "inputs")) {
				Ingredient ing = Ingredient.fromJson(e);
				if (!ing.isEmpty()) {
					inputs.add(ing);
				}
			}

			int time = json.get("tick").getAsInt();
			int requireEnergy = json.get("requireEnergy").getAsInt();
			ItemStack output = ShapedRecipe.itemStackFromJson(json.getAsJsonObject("output"));

			return new SPCRecipe(id, output, inputs.toArray(new Ingredient[0]), requireEnergy, time);
		}

		@Nullable
		@Override
		public SPCRecipe fromNetwork(ResourceLocation id, FriendlyByteBuf pBuffer) {
			ItemStack output = pBuffer.readItem();
			int tick = pBuffer.readVarInt();
			int requireEnergy = pBuffer.readVarInt();
			int length = pBuffer.readVarInt();
			Ingredient[] inputs = new Ingredient[length];
			for (int i = 0; i < length; i++) {
				inputs[i] = Ingredient.fromNetwork(pBuffer);
			}
			return new SPCRecipe(id, output, inputs, requireEnergy, tick);
		}

		@Override
		public void toNetwork(FriendlyByteBuf pBuffer, SPCRecipe pRecipe) {
			pBuffer.writeItem(pRecipe.output);
			pBuffer.writeVarInt(pRecipe.tick);
			pBuffer.writeVarInt(pRecipe.requireEnergy);
			pBuffer.writeVarInt(pRecipe.inputs.length);
			for (Ingredient ingredient : pRecipe.inputs) {
				ingredient.toNetwork(pBuffer);
			}
		}

	}

}
